package org.example.seata.common.security.config.resource;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.example.seata.common.security.util.SecurityUtil;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Component;

/**
 * @author hzq
 * @date 2021/12/17 11:39
 */
@Slf4j
@Aspect
@Component
public class CustomSecurityInnerAspect implements Ordered {

    /**
     * 类上 方法上 都会触发拦截 （方法上的优先）
     * 此时传入的inner为方法上的 如果@Inner声明在类上 那么inner为空 则需获取类上的@Inner
     */
    @SneakyThrows
    @Around("@within(inner) || @annotation(inner)")
    public Object around(ProceedingJoinPoint pjp, Inner inner) {
        // 实际注入的inner实体由表达式后一个注解决定，即是方法上的@Inner注解实体，若方法上无@Inner注解，则获取类上的
        if (null == inner) {
            Class<?> clazz = pjp.getTarget().getClass();
            inner = AnnotationUtils.findAnnotation(clazz, Inner.class);
        }
        // 需要经过AOP && 不是内部调用 && 没有认证
        if (inner.value() && !SecurityUtil.internalCall() && !SecurityUtil.verified()) {
            log.warn("访问接口 {} 没有权限", pjp.getSignature().getName());
            throw new AccessDeniedException("Full authentication is required to access this resource");
        }
        return pjp.proceed();
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 1;
    }
}
